package posts

import (
	"community-service/cmd/api/internal/models/model"
	"community-service/cmd/api/internal/svc"
	"community-service/cmd/api/internal/types"
	e "community-service/pkg/errorx"
	"context"
	"fmt"
	user "gitee.com/vzerx/proto-contracts/auth"
	"github.com/zeromicro/go-zero/core/logx"
	"google.golang.org/grpc/codes"
)

type ListPostLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewListPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPostLogic {
	return &ListPostLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ListPostLogic) ListPost(req *types.PostReq) (*types.PostList, error) {
	var resp types.PostList
	postQuery := l.svcCtx.DB.WithContext(l.ctx).Model(&model.CsCommunityPost{}).
		Joins("post").
		Joins(fmt.Sprintf("INNER JOIN %s topic ON post.topic_id = topic.id", model.TableNameCsCommunityTopic))

	// 按标题模糊搜索
	if req.Name != "" {
		postQuery.Where("post.title LIKE ?", "%"+req.Name+"%")
	}

	// 按专栏筛选
	if req.MenuId > 0 {
		// 需要通过topic表关联查询
		postQuery.Where("topic.menu_id = ?", req.MenuId)
	}

	// 按话题筛选
	if req.TopicId > 0 {
		postQuery.Where("topic_id = ?", req.TopicId)
	}

	// 按状态筛选 (0待审核 1下架 2上架 3隐藏 默认4表示查询所有)
	if req.Type != types.PostTypeAll {
		postQuery.Where("status = ?", req.Type)
	}

	// 查询总数
	if err := postQuery.Count(&resp.Total).Error; err != nil {
		return nil, e.NewGrpcErr(codes.Internal, e.DBError)
	}

	postQuery.
		Joins(fmt.Sprintf("LEFT JOIN %s approve ON approve.post_id = post.id", model.TableNameCsCommunityPostApprove)).
		Joins(fmt.Sprintf("LEFT JOIN %s exp ON exp.id = post.id", model.TableNameCsCommunityPostExperimentMap)).
		Joins(fmt.Sprintf("LEFT JOIN %s comment ON comment.post_id = post.id", model.TableNameCsCommunityPostComment)).
		Select(
			"post.id", "post.topic_id", "post.title", "post.status",
			"topic.name topic_name",
			//"post.content", // List操作忽略
			"post.is_topped", "post.is_selected", "post.is_official",
			"post.view_count", "post.reason", "post.create_user", "post.create_username",
			"IFNULL(COUNT(DISTINCT approve.id), 0) as approve_count",
			fmt.Sprintf("CASE WHEN post.create_user = %d THEN 1 ELSE 0 END as owner", req.UserProfile.UserId),
			"IFNULL(COUNT(DISTINCT comment.id), 0) as comment_count",
			"UNIX_TIMESTAMP(post.created_at) as created_at",
			"UNIX_TIMESTAMP(post.updated_at) as updated_at",
			"IFNULL(exp.experiment_id, 0) as experiment_id",
			"IFNULL(exp.experiment_name, '') as experiment_name",
			"IFNULL(exp.course_resource_id, '') as course_resource_id",
			"IFNULL(exp.chapter_ref_id, '') as chapter_ref_id",
		).
		Group("post.id").
		Order("post.is_topped DESC, post.is_selected DESC, post.is_official DESC, post.created_at DESC").
		Limit(req.PageSize).Offset((req.PageNum - 1) * req.PageSize)

	// 临时结构体接收查询结果
	type PostWithExperiment struct {
		types.PostRsp
		TopicName        string `json:"topic_name"`
		ExperimentId     int64  `json:"experiment_id"`
		ExperimentName   string `json:"experiment_name"`
		CourseResourceId string `json:"course_resource_id"`
		ChapterRefId     string `json:"chapter_ref_id"`
	}

	var rawPosts []PostWithExperiment
	if err := postQuery.Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&rawPosts).Error; err != nil {
		return nil, e.NewGrpcErr(codes.Internal, e.DBError)
	}

	for _, raw := range rawPosts {
		post := &types.PostRsp{
			Id:     raw.Id,
			Title:  raw.Title,
			Status: raw.Status,
			Reason: raw.Reason,
			Topic: &types.TopicRsp{
				Id:   raw.TopicId,
				Name: raw.TopicName,
			},
			IsTopped:       raw.IsTopped,
			IsSelected:     raw.IsSelected,
			IsOfficial:     raw.IsOfficial,
			CreateUser:     raw.CreateUser,
			CreateUsername: raw.CreateUsername,
			CreatedAt:      raw.CreatedAt,
			UpdatedAt:      raw.UpdatedAt,
			ApproveCount:   raw.ApproveCount,
			ViewCount:      raw.ViewCount,
			CommentCount:   raw.CommentCount,
			Author: &types.AuthorRsp{
				Id:   raw.CreateUser,
				Name: raw.CreateUsername,
			},
		}

		if raw.ExperimentId != 0 {
			post.Experiment = &types.Experiment{
				Id:               raw.ExperimentId,
				Name:             raw.ExperimentName,
				CourseResourceId: raw.CourseResourceId,
				ChapterRefId:     raw.ChapterRefId,
			}
		}

		userInfo, err := l.svcCtx.User.GetUserInfo(l.ctx, &user.UserInfoReq{UserId: raw.CreateUser})
		if err == nil {
			post.Author = &types.AuthorRsp{
				Id:            userInfo.UserId,
				Name:          userInfo.UserName,
				Sex:           userInfo.Sex,
				Avatar:        userInfo.Avatar,
				CollageName:   userInfo.CollageName,
				SecondOrgName: userInfo.SecOrgName,
				OrgName:       userInfo.OrgName,
			}
		}
		resp.Data = append(resp.Data, post)
	}

	return &resp, nil
}
